package com.zl.basic.dao;

import com.zl.basic.CommonUtil.Check;
import com.zl.basic.model.Pager;
import com.zl.basic.model.SystemContext;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;

import javax.inject.Inject;
import java.lang.reflect.ParameterizedType;
import java.math.BigInteger;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * User: zl email:c3tc3tc3t@126.com Date: 14-1-8 Time: 下午1:10
 */
@SuppressWarnings("unchecked")
public class BaseDao<T> implements IBaseDao<T> {

  private SessionFactory sessionFactory;

  public SessionFactory getSessionFactory() {
    return sessionFactory;
  }

  @Inject
  public void setSessionFactory(SessionFactory sessionFactory) {
    this.sessionFactory = sessionFactory;
  }

  protected Session getSession() {
    return sessionFactory.getCurrentSession();
  }


  private Class<T> clz;

  /**
   * 获得泛型的class对象
   * 
   * @return
   */
  public Class<T> getClz() {
    if (null == clz) {
      clz =
          ((Class<T>) (((ParameterizedType) (this.getClass().getGenericSuperclass()))
              .getActualTypeArguments()[0]));
    }
    return clz;
  }

  /**
   * 排序设置
   * 
   * @param hql
   * @return
   */
  private String initSortkeyOrder(String hql) {

    String order = SystemContext.getOrder();
    String sortkey = SystemContext.getSortkey();
    // 排序关键字
    if (sortkey != null && !"".equals(sortkey.trim())) {
      hql += " order by " + sortkey;
      // 升序降序
      if ("desc".equals(order.trim())) {
        hql += " desc";
      } else {
        hql += " asc";
      }
    }
    return hql;
  }

  // 设置分页参数
  private void setPages(Query query, Pager<?> pager) {
    Integer pageSize = SystemContext.getPageSize();
    Integer pageOffset = SystemContext.getPageOffset();
    if (null == pageOffset || pageOffset < 0) pageOffset = 0;
    if (null == pageSize || pageSize < 0) pageSize = 15;
    pager.setSize(pageSize);
    pager.setOffset(pageOffset);
    query.setFirstResult(pageOffset).setMaxResults(pageSize);
  }



  // 别名设置 :username
  private void setAliasParameter(Query query, Map<String, Object> alis) {
    if (null != alis) {
      Set<String> keys = alis.keySet();
      for (String key : keys) {
        Object val = alis.get(key);
        if (val instanceof Collection) {
          // username in (:usernameList)
          query.setParameterList(key, (Collection) val);
        } else {
          // username=:username
          query.setParameter(key, val);
        }
      }
    }
  }

  // 设置参数 username=?
  private void setParameters(Query query, Object[] args) {
    if (null != args && args.length > 0) {
      int i = 0;
      for (Object arg : args) {
        query.setParameter(i++, arg);
      }
    }
  }


  // 将hql语句修改成可以查询数据条数的hql,count(*)不能和fetch同时使用，将fetch用空格替换掉
  private String getCountHql(String hql) {

    if (hql.contains("fetch")) {
      hql = hql.replace("fetch", " ");
    }
    String index = hql.substring(0, hql.indexOf("from"));
    if (!("".equals(index))) {
      hql = hql.replace(index, " select count(*) ");
    } else {
      hql = " select count(*) " + hql;
    }
    return hql;

  }


  @Override
  public T add(T t) {
    getSession().save(t);
    return t;
  }

  @Override
  public void update(T t) {
    getSession().update(t);
  }

  @Override
  public void delete(int id) {
    getSession().delete(this.load(id));
  }

  @Override
  public T load(int id) {
    return (T) getSession().load(getClz(), id);
  }


  public void checkObjectNull(int id) {
    T t = this.load(id);
    Check.checkAnyNull(t, "被操作的对象不存在");
  }

  public List<T> list(String hql, Object[] args) {

    return this.list(hql, args, null);
  }


  public List<T> list(String hql, Object arg) {
    return this.list(hql, new Object[] {arg});
  }


  public List<T> list(String hql) {
    return list(hql, null);
  }


  public List<T> list(String hql, Object[] args, Map<String, Object> alis) {
    hql = initSortkeyOrder(hql);
    Query query = getSession().createQuery(hql);
    setAliasParameter(query, alis);
    setParameters(query, args);
    return query.list();
  }


  public List<T> listByAlias(String hql, Map<String, Object> alis) {
    return this.list(hql, null, alis);
  }


  public Pager<T> find(String hql, Object[] args) {
    return this.find(hql, args, null);
  }


  public Pager<T> find(String hql, Object arg) {
    return this.find(hql, new Object[] {arg});
  }


  public Pager<T> find(String hql) {
    return this.find(hql, null);
  }


  public Pager<T> find(String hql, Object[] args, Map<String, Object> alis) {
    hql = initSortkeyOrder(hql);
    String countHql = getCountHql(hql);

    Query query = getSession().createQuery(hql);
    setAliasParameter(query, alis);
    setParameters(query, args);
    // 得到查询数据总条数的query
    Query countQuery = getSession().createQuery(countHql);
    setAliasParameter(countQuery, alis);
    setParameters(countQuery, args);

    Pager<T> pager = new Pager<>();
    setPages(query, pager);
    long total = (Long) countQuery.uniqueResult();
    List<T> datas = query.list();
    pager.setDatas(datas);
    pager.setTotal(total);
    return pager;
  }


  public Pager<T> findByAlias(String hql, Map<String, Object> alis) {
    return this.find(hql, null, alis);
  }


  public Object queryObjectByHql(String hql, Object[] args) {

    return this.queryObjectByHql(hql, args, null);
  }


  public Object queryObjectByHql(String hql, Object arg) {
    return this.queryObjectByHql(hql, new Object[] {arg});
  }


  public Object queryObjectByHql(String hql) {
    return this.queryObjectByHql(hql, null);
  }


  public Object queryObjectByHql(String hql, Object[] args, Map<String, Object> alias) {
    Query query = getSession().createQuery(hql);
    setAliasParameter(query, alias);
    setParameters(query, args);
    return query.uniqueResult();
  }


  public Object queryObjectByAliasHql(String hql, Map<String, Object> alias) {
    return this.queryObjectByHql(hql, null, alias);
  }


  public void updateByHql(String hql, Object[] args) {
    this.updateByHql(hql, args, null);
  }



  public void updateByHql(String hql, Object arg) {
    this.updateByHql(hql, new Object[] {arg});
  }


  public void updateByHql(String hql) {
    this.updateByHql(hql, null);
  }



  public void updateByHql(String hql, Object[] args, Map<String, Object> alias) {

    Query query = getSession().createQuery(hql);
    setAliasParameter(query, alias);
    setParameters(query, args);
    query.executeUpdate();
  }


  public void updateByAliasHql(String hql, Map<String, Object> alias) {
    this.updateByHql(hql, null, alias);
  }


  public <N> List<N> listBySql(String sql, Object[] args, Class<?> clz, boolean hasEntity) {
    return this.listBySql(sql, args, null, clz, hasEntity);
  }


  public <N> List<N> listBySql(String sql, Object arg, Class<?> clz, boolean hasEntity) {
    return this.listBySql(sql, new Object[] {arg}, null, clz, hasEntity);
  }


  public <N> List<N> listBySql(String sql, Class<?> clz, boolean hasEntity) {
    return this.listBySql(sql, null, clz, hasEntity);
  }


  public <N> List<N> listBySql(String sql, Object[] args, Map<String, Object> alias, Class<?> clz,
      boolean hasEntity) {
    sql = initSortkeyOrder(sql);
    SQLQuery sq = getSession().createSQLQuery(sql);
    setAliasParameter(sq, alias);
    setParameters(sq, args);
    if (hasEntity) {
      // 如果是hibernate管理的实体
      sq.addEntity(clz);
    } else {
      sq.setResultTransformer(Transformers.aliasToBean(clz));
    }
    return sq.list();
  }


  public <N> List<N> listByAliasSql(String sql, Map<String, Object> alias, Class<?> clz,
      boolean hasEntity) {
    return this.listBySql(sql, null, alias, clz, hasEntity);
  }


  public <N> Pager<N> findBySql(String sql, Object[] args, Class<?> clz, boolean hasEntity) {
    return this.findBySql(sql, args, null, clz, hasEntity);
  }


  public <N> Pager<N> findBySql(String sql, Object arg, Class<?> clz, boolean hasEntity) {
    return this.findBySql(sql, new Object[] {arg}, clz, hasEntity);
  }


  public <N> Pager<N> findBySql(String sql, Class<?> clz, boolean hasEntity) {
    return this.findBySql(sql, null, clz, hasEntity);
  }


  public <N> Pager<N> findBySql(String sql, Object[] args, Map<String, Object> alias, Class<?> clz,
      boolean hasEntity) {
    sql = initSortkeyOrder(sql);
    String countsql = getCountHql(sql);


    SQLQuery sq = getSession().createSQLQuery(sql);
    SQLQuery csq = getSession().createSQLQuery(countsql);


    setAliasParameter(sq, alias);
    setParameters(sq, args);

    setAliasParameter(csq, alias);
    setParameters(csq, args);

    Pager<N> pager = new Pager<>();

    setPages(sq, pager);

    if (hasEntity) {
      sq.addEntity(clz);
    } else {
      sq.setResultTransformer(Transformers.aliasToBean(clz));
    }

    pager.setDatas(sq.list());
    Long total = ((BigInteger) csq.uniqueResult()).longValue();
    pager.setTotal(total);


    return pager;
  }


  public <N> Pager<N> findByAliasSql(String sql, Map<String, Object> alias, Class<?> clz,
      boolean hasEntity) {
    return this.findBySql(sql, null, alias, clz, hasEntity);
  }
}
